package com.xiyuan.smartutils;

import com.xiyuan.smartutils.loader.SystemLoader;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.file.FileSystems;
import java.util.*;

/**
 * 系统相关工具类
 *
 * @version v1.0.0 @author xiyuan-lgz 2020-8-27 新建与整理
 * <pre>
 * 键相关值的描述 o
 * s.name 操作系统的名称
 * os.arch 操作系统的架构
 * os.version 操作系统的版本
 * user.name 用户的账户名称
 * user.home 用户的主目录
 * user.dir 用户的当前工作目录
 * file.separator 文件分隔符（在 UNIX 系统中是“/”）
 * path.separator 路径分隔符（在 UNIX 系统中是“:”）
 * line.separator 行分隔符（在 UNIX 系统中是“/n”）
 * java.version Java 运行时环境版本
 * java.vendor Java 运行时环境供应商
 * java.vendor.url Java 供应商的 URL
 * java.home
 * Java 安装目录
 * java.vm.specification.version Java 虚拟机规范版本
 * java.vm.specification.vendor Java 虚拟机规范供应商
 * java.vm.specification.name Java 虚拟机规范名称
 * java.vm.version Java 虚拟机实现版本
 * java.vm.vendor Java 虚拟机实现供应商
 * java.vm.name Java 虚拟机实现名称
 * java.specification.version Java  运行时环境规范版本
 * java.specification.vendor Java 运行时环境规范供应商
 * java.specification.name Java 运行时环境规范名称
 * java.class.version Java 类格式版本号 java.class.path Java 类路径
 * java.library.path 加载库时搜索的路径列表
 * java.io.tmpdir 默认的临时文件路径
 * java.compiler 要使用的 JIT 编译器的名称
 * java.ext.dirs 一个或多个扩展目录的路径
 * 等参数信息
 * </pre>
 */

@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
public final class Systems {
    private static Systems INSTANCE = null;
    public static final int JAVA_MAIN_VERSION;
    public static final String OS_NAME;
    
    static {
        String property = System.getProperty("java.specification.version");
        if (property.startsWith("1.")) {
            property = property.substring(2);
        }
        JAVA_MAIN_VERSION = Integer.parseInt(property);
        OS_NAME = System.getProperty("os.name");
    }
    
    ClassLoader loader = null;
    Method defineClass = null;
    
    private Systems() throws Throwable {
//        SystemLoader.init();
        loader = this.getClass().getClassLoader();
        defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
    }
    
    public static String getLibSuffix() {
        if (isWindows()) {
            return ".dll";
        }
        else if (isMacOS()) {
            return ".dylib";
        }
        else {
            // 默认用linux 文件
            return ".so";
        }
    }
    /*******************************************************************/
    // 常用的判断和获取方法
    /*******************************************************************/
    
    /**
     * 判断是否是Windows
     */
    public static boolean isWindows() {
        return OS_NAME.toLowerCase().startsWith("windows");
    }
    
    /**
     * 判断是否是MacOS
     */
    public static boolean isMacOS() {// Mac OS X || Darwin
        String ss = OS_NAME.toLowerCase();
        return ss.startsWith("mac") || ss.startsWith("darwin");
    }
    
    /**
     * 判断是否是Linux
     */
    public static boolean isLinux() {
        return OS_NAME.toLowerCase().startsWith("linux");
    }
    
    /**
     * 获取工程进程ID
     */
    public static int getPid() {
        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        String name = runtime.getName(); // 得到的格式: "pid@hostname"
        // 处理没有@符号的情况（某些JVM实现）
        return Ints.toInt(!name.contains("@") ? name : name.split("@")[0], -1);
    }
    
    /**
     * JAVA版本号是否1.7以上(含1.5)
     */
    public static boolean isJavaVersionMoreThen5() {
        return getJavaVersion().compareTo("1.5") >= 0;
    }
    
    /**
     * JAVA版本号是否1.6以上(含1.6)
     */
    public static boolean isJavaVersionMoreThen6() {
        return JAVA_MAIN_VERSION >= 6;
    }
    
    /**
     * JAVA版本号是否1.7以上(含1.7)
     */
    public static boolean isJavaVersionMoreThen7() {
        return JAVA_MAIN_VERSION >= 7;
    }
    
    /**
     * JAVA版本号是否1.8以上(含1.8)
     */
    public static boolean isJavaVersionMoreThen8() {
        return JAVA_MAIN_VERSION >= 8;
    }
    
    public static boolean isJavaVersionMoreThen11() {
        return JAVA_MAIN_VERSION >= 11;
    }
    
    public static boolean isJavaVersionMoreThen17() {
        return JAVA_MAIN_VERSION >= 17;
    }
    
    public static boolean isJavaVersionMoreThen21() {
        return JAVA_MAIN_VERSION >= 21;
    }
    
    /**
     * 等同于getPathSeparator
     */
    public static String getClassPathSeparator() {
        return getPathSeparator();
    }
    
    /**
     * 增加库路径
     */
    public static void addLibraryPath(String dir) {
        String libraryPath = System.getProperty("java.library.path");
        String sp = getClassPathSeparator();
        Set<String> set = Arrays.newHashSet(libraryPath.split(sp));
        System.setProperty("java.library.path", dir + sp + StrUtils.join(sp, set));
    }
    
    /**
     * 增加库路径
     */
    public static void addLibraryPaths(Collection<String> dirs) {
        String libraryPath = System.getProperty("java.library.path");
        String sp = getClassPathSeparator();
        Set<String> set = new LinkedHashSet<>(dirs);
        String[] arr = libraryPath.split(sp);
        set.addAll(java.util.Arrays.asList(arr));
        System.setProperty("java.library.path", StrUtils.join(sp, set));
    }
    
    /**
     * 获取类路径信息通过分隔符成数组
     */
    public static String[] getClassPaths() {
        String[] pss = Arrays.toStringArray(getClassPath(), getClassPathSeparator());
        
        return !isWindows()
               ? pss
               : Arrays.stream(pss).map(path -> path.replaceAll("\\\\", "/")).toArray(String[]::new);
    }
    
    /**
     * 获取类路径信息通过分隔符成列表
     */
    public static List<String> getClassPathList() {
        return Lists.toStringList(getClassPath(), getClassPathSeparator());
    }
    
    public static void setClassPath(String classPath) {
        System.setProperty("java.class.path", classPath);
    }
    
    /*******************************************************************/
    // 属性设置获取等基本操作方法
    /*******************************************************************/
    
    /**
     * 设置属性
     */
    public static void setProperty(String key, String value) {
        System.setProperty(key, value);
    }
    
    /**
     * 获取属性
     */
    public static String getProperty(String key) {
        return System.getProperty(key);
    }
    
    /**
     * 获取环境变量
     */
    public static String getEnv(String key) {
        return System.getenv(key);
    }
    
    /**
     * 获取属性或环境变量，优先属性
     */
    public static String getPropOrEnv(String key) {
        String value = System.getProperty(key);
        return (value == null) ? System.getenv(key) : value;
    }
    
    /**
     * 替换属性
     */
    public static String replaceProperty(String str) {
        if (Validates.isEmpty(str)) {
            return str;
        }
        
        while (true) {
            int sInd = str.indexOf("${");
            if (sInd == -1) {
                break;
            }
            
            int eInd = str.indexOf("}", sInd + 2);
            if (eInd == -1 || eInd <= sInd + 2) {
                break;
            }
            
            String env = str.substring(sInd + 2, eInd);
            String value = getProperty(env);
            str = Replaces.replaceAllEscape(str, "${" + env + "}", value);
        }
        
        return str;
    }
    
    /**
     * 替换路径属性
     */
    public static String replacePropertyPath(String str) {
        return (Validates.isEmpty(str)) ? str : Replaces.replaceAllEscape(replaceProperty(str), "\\", "/");
    }
    
    /*******************************************************************/
    // 属性常用的获取方法
    /*******************************************************************/
    
    /**
     * 获取操作系统名称
     */
    public static String getOsName() {
        return StrUtils.trimToEmpty(System.getProperty("os.name"));
    }
    
    
    /**
     * 获取操作系统的架构
     */
    public static String getOsArch() {
        return System.getProperty("os.arch");
    }
    
    /**
     * 获取操作系统的架构
     */
    public static String getOsVersion() {
        return System.getProperty("os.version");
    }
    
    /**
     * 获取用户账号名称
     */
    public static String getUserName() {
        return System.getProperty("user.name");
    }
    
    /**
     * 获取用户主目录
     */
    public static String getUserHome() {
        return System.getProperty("user.home");
    }
    
    /**
     * 获取用户当前工作目录(工程根目录)
     */
    public static String getUserDir() {
        return System.getProperty("user.dir");
    }
    
    /**
     * 取得系统的文件分隔符，在window系统返回"\"，在unix/linux系统返回"/"
     */
    public static String getFileSeparator() {
        return FileSystems.getDefault().getSeparator();
    }
    
    /**
     * 取得系统的路径分隔符，在window系统返回";"，在unix/linux系统返回":"）
     */
    public static String getPathSeparator() {
        return File.pathSeparator;
    }
    
    /**
     * 取得系统的行分隔符，在window系统返回"\r\n"，在unix/linux系统返回"\n"
     */
    public static String getLineSeparator() {
        return System.lineSeparator();
    }
    
    /**
     * 获取JAVA版本号，返回如1.4,1.5
     */
    public static String getJavaVersion() {
        return System.getProperty("java.version");
    }
    
    public static String getJavaVendor() {
        return System.getProperty("java.vendor");
    }
    
    
    public static String getJavaHome() {
        String javaHome = System.getProperty("java.home");
        return StrUtils.trimRight(javaHome.replaceAll("\\\\", "/"), "/");
    }
    
    /**
     * 获取全类路径信息
     */
    public static String getClassPath() {
        return System.getProperty("java.class.path");
    }
    
    /**
     * 获取加载库时搜索的库路径列表
     */
    public static String getLibraryPath() {
        return System.getProperty("java.library.path");
    }
    
    public static List<String> getLibraryPaths() {
        return Arrays.asList(System.getProperty("java.library.path").split(getPathSeparator()));
    }
    
    /**
     * 获取虚拟机信息
     */
    public static String getVmInfo() {
        return System.getProperty("java.vm.info");
    }
    
    /**
     * 获取虚拟机名称
     */
    public static String getVmName() {
        return System.getProperty("java.vm.name");
    }
    
    /**
     * 获取虚拟机版本
     */
    public static String getVmVersion() {
        return System.getProperty("java.vm.version");
    }
    
    /**
     * 获取系统工程文件编码
     */
    public static String getFileEncoding() {
        return Charset.defaultCharset().displayName();
    }
    
    /**
     * 获取系统编码
     */
    public static String getSystemEncoding() {
        return System.getProperty("sun.jnu.encoding");
    }
    
    /**
     * 获取主机名
     */
    public static String getHostname() {
        try {
            InetAddress localMachine = InetAddress.getLocalHost();
            return localMachine.getCanonicalHostName();
        }
        catch (UnknownHostException e) {
            return "localhost";
        }
    }
    
    /**
     * 获取运行时的参数列表
     *
     * @return 参数列表
     */
    public static List<String> getInputArguments() {
        return SystemLoader.getInputArguments();
    }
    
    /**
     * 判断是否为debug 启动
     *
     * @return true|false
     */
    public static boolean isDebug() {
        return SystemLoader.isDebug();
    }
    
    
    /**
     * 是否为开发环境
     *
     * @return true | false
     */
    public static boolean isDev() {
        return SystemLoader.isDevelopmentEnvironment();
    }
    
    static {
        try {
            INSTANCE = new Systems();
        }
        catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}
